package com.sunseaypw.console;

import java.util.Arrays;

import javax.annotation.PreDestroy;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;

public class SprintAop {
    public static void main(String[] args){
        ApplicationContext ctx =new ClassPathXmlApplicationContext("application888.xml");
        var aa=(BeanAAA)ctx.getBean("beanAAA");
        aa.showMe();
        var bb=(BeanBBB)ctx.getBean("beanBBB");
        bb.showMe();

        var cc=(BeanCCC)ctx.getBean("beanCCC");
        cc.hello("###这就是个传说###");
    }
    
    @Aspect
    public static class MyAspect666{
        public MyAspect666(){
            System.out.println("MyAspect66666666 注册上了");
        }
        @Pointcut("execution(void *..*.hello*(..))")
        private void pointCut111(){
        }
        /** 参数必填 引用pointcut方法() 或者直接定义pointcut execute()等 */
        @After("pointCut111()")
        public void after(JoinPoint jp){
            System.out.println("MyAspect8888888888888888888888888888 after 方法签名："+jp.getSignature());
        }
    }

    public static class MyAspect{
        /**
         * 前置通知:数据校验，身份校验
         * @param jp 连接点参数Joinpoint，必须放在方法的第一位，可对切入点进行分析
         *           比如拿连接点对应的方法签名信息，连接点的目标对象实例，连接点的参数信息
         */
        public void before(JoinPoint jp){
            System.out.println("MyAspect before 连接点所在方法的签名信息："+jp.getSignature().toLongString()
                    +" 代理的target对象："+jp.getTarget().getClass().toString()
                    +" 代理的方法当前传递参数信息："+Arrays.toString(jp.getArgs()));
        }
        /**
         * 环绕通知:事务控制，权限控制，返回对象
         * @param pjp 对连接点的方法内容进行整体控制
         * @return 返回连接点的返回值
         * @throws Throwable 连接点有异常则抛出
        */
        public Object around(ProceedingJoinPoint pjp) throws Throwable{            
            System.out.println("MyAspect around 环绕前置 连接点所在方法的签名信息："+pjp.getSignature().toLongString()
                    +" 代理的target对象："+pjp.getTarget().getClass().toString()
                    +" 代理的方法当前传递参数信息："+Arrays.toString(pjp.getArgs()));
            Object obj = pjp.proceed(); //调用核心业务
            System.out.println("MyAspect around 环绕返回对象："+(obj==null?"null":obj.toString()));
		    System.out.println("MyAspect around 环绕后置， 在执行用辅助业务");
            return obj;
        }
        /**
         * 后置通知:日志记录，返回对象
         * 前面异常后，也会调用此处
         * @param jp 连接点的基本信息
         * @param result 获取连接点的返回对象
        */
        public void returnAfter(JoinPoint jp,Object result){
            System.out.println("MyAspect returnAfter 连接点所在方法的签名信息："+jp.getSignature().toLongString()
                    +" 代理的target对象："+jp.getTarget().getClass().toString()
                    +" 代理的方法当前传递参数信息："+Arrays.toString(jp.getArgs())
                    +" 返回结果信息："+(result==null?"null":result.toString()));
        }
        /**
         * 最终通知:在方法最后执行
         * @param jp 连接点的基本信息
        */
        public void after(JoinPoint jp){
            System.out.println("MyAspect after 连接点所在方法的签名信息："+jp.getSignature().toLongString()
                    +" 代理的target对象："+jp.getTarget().getClass().toString()
                    +" 代理的方法当前传递参数信息："+Arrays.toString(jp.getArgs()));
        }
        /**
         * 异常通知:异常处理，事务控制
         * 在目标方法抛出异常时执行的通知
         * @param jp 连接点的基本信息
         * @param e 连接点的异常信息
        */
        public void afterThrow(JoinPoint jp,Throwable e){
            System.out.println("MyAspect afterThrow 连接点所在方法的签名信息："+jp.getSignature().toLongString()
                    +" 代理的target对象："+jp.getTarget().getClass().toString()
                    +" 代理的方法当前传递参数信息："+Arrays.toString(jp.getArgs())
                    +" 异常信息："+e.toString());
        }
    }
    public static class MyAspect222{
        /**
         * 前置通知:数据校验，身份校验
         * @param jp 连接点参数Joinpoint，必须放在方法的第一位，可对切入点进行分析
         *           比如拿连接点对应的方法签名信息，连接点的目标对象实例，连接点的参数信息
         */
        public void before(JoinPoint jp){
            System.out.println("MyAspect222222222222222222  before");
        }
        /**
         * 环绕通知:事务控制，权限控制，返回对象
         * @param pjp 对连接点的方法内容进行整体控制
         * @return 返回连接点的返回值
         * @throws Throwable 连接点有异常则抛出
        */
        public Object around(ProceedingJoinPoint pjp) throws Throwable{            
            System.out.println("MyAspect22222222222222222 around 环绕前置 ");
            Object obj = pjp.proceed(); //调用核心业务
            System.out.println("MyAspect22222222222222222 around 环绕后置  ");
            return obj;
        }
        /**
         * 后置通知:日志记录，返回对象
         * 前面异常后，也会调用此处
         * @param jp 连接点的基本信息
         * @param result 获取连接点的返回对象
        */
        public void returnAfter(JoinPoint jp,Object result){
            System.out.println("MyAspect22222222222222222 returnAfter");
        }
        /**
         * 最终通知:在方法最后执行
         * @param jp 连接点的基本信息
        */
        public void after(JoinPoint jp){
            System.out.println("MyAspect22222222222222222 after ");
        }
        /**
         * 异常通知:异常处理，事务控制
         * 在目标方法抛出异常时执行的通知
         * @param jp 连接点的基本信息
         * @param e 连接点的异常信息
        */
        public void afterThrow(JoinPoint jp,Throwable e){
            System.out.println("MyAspect22222222222222222 afterThrow ");
        }
    }    
    public static class MyAspect333{
        public void before(JoinPoint jp){
            System.out.println("MyAspect3333333333333*******************  before 方法："+jp.getSignature());
        }
    }    
    public static class BeanCCC extends BeanCCC_Parent{        
    }
    public static @interface MyAnnotation{        
    }
    @Controller
    public static class BeanCCC_Parent{
        @MyAnnotation
        public void hello(String word)throws RuntimeException{
            System.out.println("父类父类正常显示的内容:::"+word);
        }
    }

    /* 自定义processor 注册为bean后会被容器识别，并作为特殊bean来处理，并作为处理其他bean的处理器
    */
    public static class MyBeanPostProcesor implements BeanPostProcessor{
        public java.lang.Object postProcessBeforeInitialization(java.lang.Object bean, java.lang.String beanName) throws org.springframework.beans.BeansException {
            System.out.println("MyBeanPostProcesor postProcessBeforeInitialization trigge :::"+beanName);
            switch(beanName){
                case "beanAAA":
                    ((BeanAAA)bean).setTitle("MyBeanPostProcesor 注入title为：AAAAAAAAAAAAAAAA");
                    break;
                case "beanBBB":
                    ((BeanBBB)bean).setTitle("MyBeanPostProcesor 注入title为：BBBBBBBBBBBBBBBB");
                    break;
            }            
            return bean;
        }        
        public java.lang.Object postProcessAfterInitialization(java.lang.Object bean, java.lang.String beanName) throws org.springframework.beans.BeansException {
            System.out.println("MyBeanPostProcesor postProcessAfterInitialization trigge :::"+beanName);
            return bean;
        }
    }
    public static class BeanAAA{
        String title;
        public void setTitle(String title){
            this.title=title;
        }
        public void showMe(){
            System.out.println("BeanAAAAAAAAA my title is::::"+this.title);
        }
    }
    public static class BeanBBB{
        String title;
        public void setTitle(String title){
            this.title=title;
        }
        public void showMe(){
            System.out.println("BeanBBBBBBBBB my title is::::"+this.title);
        }
    }
}